package plgnet

/**
  该插件不支持注册多个实例, 创建后不支持销毁
*/
import (
	"dgo/MyProj/PrjHttpUtils"
	"dgo/goutils/gohttp"
	"dgo/goutils/httpfs"
	"dgo/goutils/utils"
	"dgo/plg/plgbase"
	"fmt"
	"gitee.com/ymofen/supervalue"
	"net/http"
	"os"
	"strings"
	"time"
)

type NetHttpUploadPlg struct {
	plgbase.PlgBase
	Http_allow_cross_access bool
	plugId                  string
	pattern                 string
	home                    string
	max_size                int64
	def_existsflag          int

	view_pattern   string
	view_listtype  string
	view_listfiles bool

	msglst       *utils.SyncCycleList
	jsonrespflag int8
}

/*
*

		{
			"id": "res-upload",
			"type": "net.http.fileupload",
			"conf": {
			  "http-allow-cross-access":true,
			  "json-respflag":1,
			  "existsflag-def":2,
			  "pattern":"/res/upload",
			  "root":"C:/appres/",
	          "view-pattern":"/res",
	          "view-listfiles":true

			}
	    },

// existsflag-def 文件

	0: 重命名上传文件名
	1：默认，覆盖
	2：重命名之前的文件_DATEID_RAND4, 重命名失败会返回错误
*/
func (this *NetHttpUploadPlg) ReloadConf(conf *wrapper.SuperValue) error {

	this.jsonrespflag = int8(conf.IntByName("json-respflag", 0))

	conf.CheckExistsStrFunc("http-allow-cross-access", func(strv string) {
		this.Http_allow_cross_access = utils.TryStrToBool(strv, false)
	})

	if this.msglst == nil {
		this.msglst = utils.NewSyncCycleList()
	}

	conf.CheckStrFunc("pattern", func(strv string) {
		if this.pattern != strv {
			gohttp.CheckDefaultHttpServeMux("/")
			if len(this.pattern) > 0 {
				gohttp.UnHandle(this.pattern)
			}
			this.pattern = strv
			if len(this.pattern) > 0 {
				gohttp.HandleFunc(this.pattern, this.UploadFile)
			}
		}
	})

	lvViewChanged := false

	conf.CheckStrFunc("root", func(strv string) {
		if this.home != strv {
			this.home = strv
			lvViewChanged = true
		}
	})

	view_pattern_0 := this.view_pattern
	conf.CheckStrFunc("view-pattern", func(strv string) {
		if this.view_pattern != strv {
			lvViewChanged = true
			this.view_pattern = strv
		}
	})

	conf.CheckStrFunc("view-listtype", func(strv string) {
		if this.view_listtype != strv {
			this.view_listtype = strv
			lvViewChanged = true
		}
	})

	conf.CheckStrFunc("view-listfiles", func(strv string) {
		b := utils.TryStrToBool(strv, true)
		if b != this.view_listfiles {
			lvViewChanged = true
			this.view_listfiles = b
		}
	})

	if lvViewChanged {
		if len(view_pattern_0) > 0 {
			gohttp.UnHandle(view_pattern_0)
		}
		if len(this.view_pattern) > 0 {
			if len(this.view_listtype) == 0 {
				this.view_listtype = "html"
			}
			lsttype := 0
			if strings.ToLower(this.view_listtype) == "json" {
				lsttype = 1
			}
			fserv := httpfs.FileServer(http.Dir(this.home), lsttype, func(w http.ResponseWriter, r *http.Request) bool {
				if this.Http_allow_cross_access {
					PrjHttpUtils.AllowCrossAccessSet(w)
				}
				return true
			})
			fserv.ListFiles = this.view_listfiles
			this.LogInfoMessage("pattern:[%s], path:[%s], listtype:%s, listfiles:%s", this.view_pattern, this.home, this.view_listtype, utils.Bool2Str(this.view_listfiles))
			gohttp.Handle(this.view_pattern, http.StripPrefix(this.view_pattern, fserv))
		}
	}

	this.def_existsflag = conf.IntByName("existsflag-def", 1)

	return nil
}

func (this *NetHttpUploadPlg) OnHttpStatus(rec *PlgHttpRec) (rval interface{}, errcode int, err error) {
	itype := rec.QryAsInt("type", 0)
	if itype == 99 {
		json := wrapper.NewSVObject()
		json.SetKeyValue("existsflag-def", this.def_existsflag)
		json.SetKeyValue("home", this.home)
		json.SetKeyValue("pattern", this.pattern)
		json.SetKeyValue("http-allow-cross-access", this.Http_allow_cross_access)
		json.SetKeyValue("jsonrespflag", this.jsonrespflag)
		json.SetKeyValues("now", utils.NowString())
		if rec.QryAsInt("json", 0) == 1 {
			PrjHttpUtils.ResponseAsJSON(rec.RespW, json.AsJSONStringEx(false, true))
		} else {
			PrjHttpUtils.JSON2TableRec(rec.RespW, "", json.AsJSONString(false))
		}
	} else if itype == 98 {
		rec.ResponseSyncListNEx(this.msglst)
	} else if itype == 1 {
		json := wrapper.NewSVArray()
		//searchval := rec.QryAsString("searchval", "")
		//this.lstDevice.ListRangeV2(func(key, value interface{}) bool {
		//	//dev := value.(*YsledMqttWebServDevice)
		//	ok := true
		//	if len(searchval) > 0 {
		//
		//	}
		//	return ok
		//}, func(k0, v0, k1, v1 interface{}) bool {
		//	return true
		//}, func(key, val interface{}) bool {
		//	return true
		//})

		if rec.QryAsInt("json", 0) == 1 {
			PrjHttpUtils.ResponseAsJSON(rec.RespW, json.AsJSONStringEx(false, false))
		} else {
			PrjHttpUtils.JSON2Table(rec.RespW, "", json.AsJSONString(false))
		}
	} else {
		var sb utils.BytesBuilder
		PrjHttpUtils.AppendIndexBody(&sb, "status", "status?type=99")
		PrjHttpUtils.AppendIndexBody(&sb, "msglist", "status?type=98&n=100&searchval=")
		PrjHttpUtils.ResponseBodyHtml(rec.RespW, sb.String())
	}
	return
}

func (this *NetHttpUploadPlg) LogInfoMessage(s string, args ...interface{}) {
	this.msglst.LogMsg(s, args...)
	utils.Log.Msgf(this.PlugId, utils.LogLV_INFO, 1, s, args...)
}

func (this *NetHttpUploadPlg) LogWarnMessage(s string, args ...interface{}) {
	this.msglst.LogMsg(s, args...)
	utils.Log.Msgf(this.PlugId, utils.LogLV_WARN, 1, s, args...)
}

func (this *NetHttpUploadPlg) OnObjectNotify(sender interface{}, notifytype int, data interface{}) (rval interface{}, err error) {
	if notifytype == utils.NOTIFY_TYPE_SETCONF {
		if conf, ok := data.(*wrapper.SuperValue); ok {
			err = this.ReloadConf(conf)
		} else {
			err = fmt.Errorf("非法的JSON配置")
		}
	} else if notifytype == utils.NOTIFY_TYPE_RELEASE {
		if len(this.pattern) > 0 {
			gohttp.UnHandle(this.pattern)
		}
		if len(this.view_pattern) > 0 {
			gohttp.UnHandle(this.view_pattern)
		}
	}
	return
}

func CreateHttpFileUploadFunc(args ...interface{}) (rval interface{}, err error) {
	obj := &NetHttpUploadPlg{def_existsflag: 1, max_size: 1024 * 1024 * 200}

	rval = obj
	return
}

/*
*

	url: upload?existsflag=0

	multiform:
	  filename:["xxx", "xx1"]
	  upfile: [FILE, FILE]
*/
func (this *NetHttpUploadPlg) UploadFile(w http.ResponseWriter, r *http.Request) {
	if this.Http_allow_cross_access {
		PrjHttpUtils.AllowCrossAccessSet(w)
	}

	err := r.ParseMultipartForm(this.max_size)
	if err != nil {
		if this.jsonrespflag == 1 {
			PrjHttpUtils.ResponseJSONValues(w, "code", -1, "msg", fmt.Sprintf("解析MultiPartForm出现异常:%s", err.Error()))
			return
		}
		http.Error(w, fmt.Sprintf("解析MultiPartForm出现异常:%s", err.Error()), 503)
		return
	}

	strFileNames := r.MultipartForm.Value["filename"]

	files := r.MultipartForm.File["upfile"]
	if len(files) == 0 {
		files = r.MultipartForm.File["file"]
		if len(files) == 0 {
			if this.jsonrespflag == 1 {
				PrjHttpUtils.ResponseJSONValues(w, "code", -1, "msg", fmt.Sprintf("没有指定上传文件(%s)参数", "upfile"))
				return
			}
			http.Error(w, fmt.Sprintf("没有指定上传文件(%s)参数", "upfile"), 503)
			return
		}
	}

	tmpFile, err1 := files[0].Open()
	if err1 != nil {
		if this.jsonrespflag == 1 {
			PrjHttpUtils.ResponseJSONValues(w, "code", -1, "msg", fmt.Sprintf("打开文件出现异常:%s", err.Error()))
			return
		}
		http.Error(w, fmt.Sprintf("打开文件出现异常:%s", err.Error()), 503)
		return
	}
	strFileID := ""
	strFileID = r.URL.Query().Get("filename")
	strCopyFile := ""
	strs := r.MultipartForm.Value["copyfile"]
	if len(strs) > 0 {
		strCopyFile = strs[0]
	}

	if len(strFileID) == 0 {
		if len(strFileNames) == 0 {
			strFileID = files[0].Filename
		} else {
			if len(strFileNames[0]) == 0 {
				strFileID = fmt.Sprintf("%s.tmp", utils.RandHexString(24))
			} else {
				strFileID = strFileNames[0]
			}
		}
	}

	strFileName := this.home + strFileID
	utils.ForceCreateFilePath(strFileName)

	var existsflag int = 0

	if utils.FileIsExists(strFileName) {
		existsflagstr := r.URL.Query().Get("existsflag")
		existsflag = this.def_existsflag

		if len(existsflagstr) > 0 {
			existsflag = utils.StrToIntDef(existsflagstr, 0)
		}

		if existsflag == 2 {
			newfilename := utils.FileNameAddfix(strFileName, "", fmt.Sprintf("_%s_%s", utils.DateTimeIDString(time.Now()), utils.RandKeyString(4)))
			err = utils.RenameFile(strFileName, newfilename)
			if err != nil {
				if this.jsonrespflag == 1 {
					PrjHttpUtils.ResponseJSONValues(w, "code", -1, "msg", fmt.Sprintf("文件已经存在, 重命名之前文件异常:%s", err.Error()))
					return
				}
				http.Error(w, fmt.Sprintf("文件已经存在, 重命名之前文件异常:%s", err.Error()), 503)
				return
			}
			this.LogInfoMessage("重命名文件, 新文件：%s", newfilename)
		} else if existsflag == 0 { // 重命名
			strFileName = utils.NewFileNameIfExistsThenIncSN(strFileName)
			strFileID = strings.TrimPrefix(strFileName, this.home)
		}
	}

	_, err = utils.NewFileFromReader(strFileName, tmpFile)
	if err != nil {
		if this.jsonrespflag == 1 {
			PrjHttpUtils.ResponseJSONValues(w, "code", -1, "msg", fmt.Sprintf("存储文件异常:%s", err.Error()))
			return
		}
		http.Error(w, fmt.Sprintf("存储文件异常:%s", err.Error()), 503)
		return
	}

	if len(strCopyFile) > 0 {
		strCopyFile = ReplacePlaceholderForFileName(strCopyFile)
		strCopyFile = this.home + strCopyFile
		utils.ForceCreateFilePath(strCopyFile)
		if utils.FileIsExists(strCopyFile) {
			os.Remove(strCopyFile)
		}
		utils.CopyFile(strFileName, strCopyFile)
	}

	sz, _ := utils.FileSize(strFileName)
	this.LogInfoMessage("存储文件:%s,  文件大小:%d, existsflag:%d, filenames:%v", strFileName, sz, existsflag, strFileNames)

	PrjHttpUtils.ResponseJSONValues(w, "filename", strFileID, "filesize", sz, "fullname", strFileName, "existsflag", existsflag, "code", 0)
}
